package apierr

import (
	"encoding/json"
	common "gitee.com/xuyiping_admin/go_proto/proto/go/backend/common"
	"gitee.com/xuyiping_admin/pkg/xerr"
	"net/http"

	"github.com/gin-gonic/gin"
)

func New(code common.Error_Code) *Error {
	return &Error{err: &common.Error{
		Code: code,
		Msg:  errorMessage(code),
	}}
}

func errorMessage(code common.Error_Code) string {
	var errMessage string
	if msg, ok := common.Error_Code_name[int32(code)]; ok {
		errMessage = msg
	} else {
		errMessage = "INTERNAL_ERROR"
	}

	return errMessage
}

type Error struct {
	err *common.Error
}

func (e *Error) GetCode() common.Error_Code {
	return e.err.Code
}

func (e *Error) GetMsg() string {
	return e.err.Msg
}

func (e *Error) GetErrors() []string {
	return e.err.Errors
}

func (e *Error) Error() string {
	bs, _ := json.Marshal(e.err)
	return string(bs)
}

// Is 判断 err 和 e 是否相同
func (e *Error) Is(err error) bool {
	if gotErr, ok := err.(*Error); !ok {
		return false
	} else {
		return e.err.Code == gotErr.err.Code
	}
}

func (e *Error) MarshalJSON() ([]byte, error) {
	return json.Marshal(e.err)
}

func (e *Error) UnmarshalJSON(data []byte) error {
	var commonErr common.Error
	if err := json.Unmarshal(data, &commonErr); err != nil {
		return err
	}

	e.err = &commonErr
	return nil
}

func (e *Error) WithLocaleMessage(c *gin.Context) *Error {
	if msg := e.GetMsg(); msg != "" {
		return e.SetMessage(msg)
	}

	return e
}

func (e *Error) SetMessage(m string) *Error {
	e.err.Msg = m
	return e
}

func (e *Error) SetErrors(errMessages []string) *Error {
	e.err.Errors = errMessages
	return e
}

// With more information
func (e *Error) With(errs ...error) *Error {
	for _, err := range errs {
		e.err.Errors = append(e.err.Errors, err.Error())
	}

	return e
}

// WithContext return error with i18n message ?
func WithContext(c *gin.Context, code common.Error_Code) *Error {
	return New(code).WithLocaleMessage(c)
}

// AbortError 用来处理多种内部错误.
// 在复杂业务场景中，存在一个接口返回多种业务错误码情况，通过这个函数来统一处理
func AbortError(c *gin.Context, err error) {
	if err == nil {
		return
	}

	if e, ok := xerr.Cause(err).(*Error); ok {
		// 取默认状态码
		statusCode := DefaultErrorStatusCode(e.err.Code)
		if !shouldIgnoreCode(statusCode) {
			c.Error(e)
		}
		c.AbortWithStatusJSON(statusCode, e.WithLocaleMessage(c))
		return
	}

	c.Error(err)
	c.AbortWithStatusJSON(http.StatusInternalServerError, WithContext(c, common.Error_INTERNAL_ERROR).With(err))
}

// AbortStatusError 用来处理多种内部错误和定制返回的 http status code.
// 在复杂业务场景中，存在一个接口返回多种业务错误码情况，通过这个函数来统一处理
func AbortStatusError(c *gin.Context, httpCode int, err error) {
	if err == nil {
		return
	}

	if e, ok := xerr.Cause(err).(*Error); ok {
		c.Error(e)
		c.AbortWithStatusJSON(httpCode, WithContext(c, e.err.Code))
		return
	}

	c.Error(err)
	c.AbortWithStatusJSON(httpCode, WithContext(c, common.Error_INTERNAL_ERROR).With(err))
}

// DefaultErrorStatusCode 返回错误码对应的默认 http status code
func DefaultErrorStatusCode(code common.Error_Code) int {
	if statusCode, ok := errorStatusCode[int(code)]; ok {
		return statusCode
	}

	return http.StatusInternalServerError
}

// 错误对应默认返回的 http status code
var errorStatusCode = map[int]int{
	0:     http.StatusOK,
	10000: http.StatusUnauthorized,
	11000: http.StatusBadRequest,
	11001: http.StatusBadRequest,
	11002: http.StatusBadRequest,
	11003: http.StatusTooManyRequests,
	11100: http.StatusBadRequest,
	11200: http.StatusBadRequest,
	20000: http.StatusBadRequest,
	21000: http.StatusBadRequest,
	22000: http.StatusBadRequest,
	23000: http.StatusBadRequest,
	23001: http.StatusBadRequest,
	24000: http.StatusBadRequest,
	24100: http.StatusBadRequest,
	24101: http.StatusBadRequest,
	24102: http.StatusBadRequest,
	24103: http.StatusBadRequest,
	24104: http.StatusBadRequest,
	24400: http.StatusBadRequest,
	24500: http.StatusBadRequest,
	24501: http.StatusBadRequest,
	24502: http.StatusBadRequest,
	24520: http.StatusBadRequest,
	24521: http.StatusBadRequest,
	24522: http.StatusBadRequest,
	24523: http.StatusBadRequest,
	24524: http.StatusBadRequest,
	24525: http.StatusBadRequest,
	24526: http.StatusBadRequest,
	24527: http.StatusBadRequest,
	24528: http.StatusBadRequest,
	24600: http.StatusBadRequest,
	24601: http.StatusBadRequest,
	24602: http.StatusBadRequest,
	24603: http.StatusBadRequest,
	24700: http.StatusBadRequest,
	24701: http.StatusBadRequest,
	24702: http.StatusBadRequest,
	24704: http.StatusBadRequest,
	24705: http.StatusBadRequest,
	24706: http.StatusBadRequest,
	24707: http.StatusBadRequest,
	24800: http.StatusBadRequest,
	24801: http.StatusBadRequest,
	24802: http.StatusBadRequest,
	24803: http.StatusBadRequest,
	90000: http.StatusInternalServerError,
	90100: http.StatusBadRequest,
	90101: http.StatusBadRequest,
	90102: http.StatusBadRequest,
	91000: http.StatusInternalServerError,
}
